﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// This is used for grayscale images
    /// B = nlfilter(A, [m n], fun) applies the function fun to each m-by-n sliding block of the grayscale image A. fun is a function that accepts an m-by-n matrix as input and returns a scalar result.
    /// 
    /// c = fun(x)
    /// 
    /// fun must be a function handle.
    /// 
    /// Parameterizing Functions, in the MATLAB Mathematics documentation, explains how to provide additional parameters to the function fun.
    /// 
    /// c is the output value for the center pixel in the m-by-n block x. nlfilter calls fun for each pixel in A. nlfilter zero-pads the m-by-n block at the edges, if necessary.
    /// 
    /// B = nlfilter(A, 'indexed',...) processes A as an indexed image, padding with 1's if A is of class single or double and 0's if A is of class logical, uint8, or uint16.    /// 
    /// 
    /// </summary>
    public class nlfilter : BaseImageFilter
    {
        protected delegate int Function(Color[,] _aValue);
        protected Function m_Function = null;
        protected int m_nSizeX = 3;
        protected int m_nSizeY = 3;

        /// <summary>
        /// creates a new instance of this filter
        /// </summary>
        public nlfilter()
        {
            m_Function = new Function(DefaultFunction);
        }

        /// <summary>
        /// used by clone
        /// </summary>
        /// <param name="_nlfilter"></param>
        internal nlfilter(nlfilter _nlfilter)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public int SizeX
        {
            get { return m_nSizeX; }
            set { m_nSizeX = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public int SizeY
        {
            get { return m_nSizeY; }
            set { m_nSizeY = value; }
        }

        /// <summary>
        /// Executes nlfilter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmapCloned = (UnsafeBitmap)_bitmap.Clone();
            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;
            int x = 0;
            int y = 0;
            int ky = 0;
            int kx = 0;
            int nValue = 0;

            int nMin = 0;
            int nMax = 0;

            int nXLeft = m_nSizeX - 1;
            int nXRight = nWidth - (m_nSizeX - 1);
            int nYLeft = m_nSizeY - 1;
            int nYRight = nHeight - (m_nSizeY - 1);

            int nIntMaxValue = int.MaxValue;
            int nIntMinValue = int.MinValue;

            Color[,] aValue = new Color[m_nSizeX, m_nSizeY];

            for (y = nYLeft; y < nYRight; y++)
            {
                for (x = nXLeft; x < nXRight; x++)
                {
                    nMin = nIntMaxValue;
                    nMax = nIntMinValue;

                    for (ky = 0; ky < m_nSizeY; ky++)
                    {
                        for (kx = 0; kx < m_nSizeX; kx++)
                        {
                            aValue[kx, ky] = bitmapCloned.GetPixel(x - 1 + kx, y - 1 + ky);
                        }
                    }

                    nValue = m_Function(aValue);
                    _bitmap.SetPixel(x, y, Color.FromArgb(255, Color.FromArgb(nValue)));
                }
            }
            bitmapCloned.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_aValue"></param>
        /// <returns></returns>
        private int DefaultFunction(Color[,] _aValue)
        {
            int nSum = 1;
            int x = 0;
            int y = 0;
            for (x = 0; x < m_nSizeX; x++)
            {
                for (y = 0; y < m_nSizeY; y++)
                {
                    int nValue = (int)Math.Sqrt(_aValue[x, y].R * _aValue[x, y].R + _aValue[x, y].G * _aValue[x, y].G + _aValue[x, y].B * _aValue[x, y].B);
                    nSum += nValue;
                }
            }
            nSum /= (m_nSizeX * m_nSizeY);
            return nSum;
        }

        /// <summary>
        /// Clones this instance
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new nlfilter(this);
        }
    }
}
